/*------------------------------------------------------------------------
|                             FILE DESCRIPTION                           |
------------------------------------------------------------------------*/
/*------------------------------------------------------------------------
|  - File name     : os_mem.c
|  - Author        : zeweni
|  - Update date   : 2021.05.05
|  - Copyright(C)  : 2021-2021 zeweni. All rights reserved.
------------------------------------------------------------------------*/
/*------------------------------------------------------------------------
|                            COPYRIGHT NOTICE                            |
------------------------------------------------------------------------*/
/*
 * Copyright (C) 2021, zeweni (17870070675@163.com)

 * This file is part of Ant Real Time Operating System.

 * Ant Real Time Operating System is free software: you can redistribute 
 * it and/or modify it under the terms of the Apache-2.0 License.

 * Ant Real Time Operating System is distributed in the hope that it will 
 * be useful,but WITHOUT ANY WARRANTY; without even the implied warranty 
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * Apache-2.0 License License for more details.

 * You should have received a copy of the Apache-2.0 License.Ant Real Time
 * Operating System. If not, see <http://www.apache.org/licenses/>.
**/
/*------------------------------------------------------------------------
|                               INCLUDES                                 |
------------------------------------------------------------------------*/

#include "os_mem.h"
#include "os_cpu.h"

/*------------------------------------------------------------------------
|                             DECLARATION                                |
------------------------------------------------------------------------*/
/* None. */
/*------------------------------------------------------------------------
|                                  DATA                                  |
------------------------------------------------------------------------*/

/**
 * @brief     内存池结构体类型。
 * @details   Memory pool structure type..
**/
struct Mem_Pool
{
    os_vuint8_t *ReMemAddr;  /*!< 当前空闲内存块地址。 */
    os_vuint8_t *ReInfoAddr;  /*!<当前空闲内存块信息地址。 */
	os_vuint16_t MemBlkCnt;  /*!< 申请的内存块数量。 */
    os_vuint16_t ReLength;    /*!< 空闲内存块长度。 */
    os_vuint8_t Pool[OS_MEM_POOL_SIZE];  /*!< 内存池。Memory pool*/
};

/**
 * @brief     定义内存池,声明储存在XRAM当中。
 * @details   Define memory pool,the statement is stored in XRAM.
**/
static xdata struct Mem_Pool G_MemPool;

/**
 * @brief     内存块信息结构体类型。
 * @details   Memory block information structure type.
 * @note      内存块信息储存在内存池的顶部，向下生长。
 *            内存块储存在内存池的底部，向上生长。
 *            The memory block information is stored 
 *            at the top of the memory pool and grows downward.
 *            The memory block is stored 
 *            at the bottom of the memory pool and grows upward.
**/
struct Mem_Block
{
	volatile void **MalPtr;   /*!< 要申请内存的指针地址。*/
	os_vuint8_t *IndexAddr; /*!< 内存块首地址。 */
    os_vuint16_t Length;  /*！< 内存块长度。*/
};

/*------------------------------------------------------------------------
|                                FUNCTION                                |
------------------------------------------------------------------------*/

/**
 * @brief   内存初始化函数，对内存池进行初始化，
 *          分静态和动态两部分，内核主要使用静态方法。
 * @details The memory initialization function initializes 
 *          the memory pool,Divided into two parts,static and dynamic,
 *          the kernel mainly uses static methods.
 * @param   None.
 * @return  [OS_OK] 内存初始化成功。 The memory is initialized successfully.
 * @return  [OS_NOK] 内存初始化失败。The memory initialization failed.
**/
os_err_t AntOS_Mem_Init(void)
{

	G_MemPool.MemBlkCnt = 0;
	G_MemPool.ReLength = OS_MEM_POOL_SIZE;
    G_MemPool.ReMemAddr = G_MemPool.Pool;
	G_MemPool.ReInfoAddr = &G_MemPool.Pool[OS_MEM_POOL_SIZE];
	
	return OS_OK;
}

/**
 * @brief      动态申请内存函数。
 * @details    Dynamic application memory function.
 * @param[in]  ptr 要申请内存的指针。The pointer to apply for memory.
 * @param[in]  size 内存大小。 memory size.
 * @return     [address] 内存申请成功，返回内存块首地址给ptr指针。
 *             The memory application is successful, 
 *             and the first address of the memory block is returned for ptr.
 * @return     [OS_NULL] 内存申请失败，返回NULL空指针给ptr指针。
 *             The memory application is failed, 
 *             and the NULL pointer is returned for ptr.
**/
void *OS_Malloc(void *mptr,os_size_t msize)
{
	os_uint8_t *ptr = mptr;
	
	OS_ENTER_CRITICAL();
	
	if(OS_MEM_POOL_SIZE > 10 && msize < OS_MEM_POOL_SIZE)
	{
		G_MemPool.ReInfoAddr -= 8;
		
		((struct Mem_Block *)G_MemPool.ReInfoAddr) -> MalPtr = (void *)mptr;
		((struct Mem_Block *)G_MemPool.ReInfoAddr) -> IndexAddr = G_MemPool.ReMemAddr;
		((struct Mem_Block *)G_MemPool.ReInfoAddr) -> Length = msize;
		
		ptr = G_MemPool.ReMemAddr;
		
		G_MemPool.ReMemAddr += msize;
		G_MemPool.ReLength -= (8 + msize); 
		G_MemPool.MemBlkCnt += 1;
		
		OS_EXIT_CRITICAL();
		
		return ptr;
	}
	
	OS_EXIT_CRITICAL();
	
    return OS_NULL;
}

/**
 * @brief      释放内存函数,不支持内存碎片整理。
 * @details    Free memory function., Does not support memory defragmentation.
 * @param[in]  ptr 要释放内存的指针。The pointer to free for memory.
 * @return     [OS_OK] 内存释放成功。
 *             The memory free is successful.
 * @return     [OS_NOK] 内存释放失败，返回NULL空指针给ptr指针。
 *             The memory free is failed.
**/
os_err_t OS_Free(void *mptr)
{
	os_uint16_t index,msize,msize2;
	os_uint8_t *reMemAddr;
	os_uint8_t *reInfoAddr;
	
	OS_ENTER_CRITICAL();
	
	if(G_MemPool.MemBlkCnt && mptr != OS_NULL)
	{
		reInfoAddr = G_MemPool.ReInfoAddr;
		
		for(index = 1; index <= G_MemPool.MemBlkCnt; index++)
		{
			if(((struct Mem_Block *)reInfoAddr) -> IndexAddr == mptr)
			{
				msize = ((struct Mem_Block *)reInfoAddr) -> Length;
				reMemAddr = mptr;
				
				while(--index)
				{
					reInfoAddr -= 8;
					
					*((struct Mem_Block *)(reInfoAddr+8)) -> MalPtr = OS_NULL;
					
					((struct Mem_Block *)(reInfoAddr+8)) -> MalPtr = ((struct Mem_Block *)reInfoAddr) -> MalPtr;
					((struct Mem_Block *)(reInfoAddr+8)) -> IndexAddr = ((struct Mem_Block *)reInfoAddr) -> IndexAddr - msize;
					((struct Mem_Block *)(reInfoAddr+8)) -> Length = ((struct Mem_Block *)reInfoAddr) -> Length;	
					
					*((struct Mem_Block *)(reInfoAddr+8)) -> MalPtr = ((struct Mem_Block *)(reInfoAddr+8)) -> IndexAddr;
					
					((struct Mem_Block *)reInfoAddr) -> MalPtr = OS_NULL;
					((struct Mem_Block *)reInfoAddr) -> IndexAddr = OS_NULL;
					((struct Mem_Block *)reInfoAddr) -> Length = 0;
					
					msize2 = msize;
					
					while(msize2--)
					{
						*(reMemAddr) = *(reMemAddr+msize);
						*(reMemAddr+msize) = 0;
						reMemAddr++;
					}
				}
			
				G_MemPool.MemBlkCnt -= 1;
				G_MemPool.ReLength  += (msize + 8);
				G_MemPool.ReInfoAddr += 8;
				G_MemPool.ReMemAddr -= msize;
				
				OS_EXIT_CRITICAL();
				return OS_OK;
				
			}
			reInfoAddr += 8;
		}
	}
	OS_EXIT_CRITICAL();
	return OS_NOK;
}


/*------------------------------------------------------------------------
|                    END OF FLIE.  (C) COPYRIGHT zeweni                  |
------------------------------------------------------------------------*/